#include <Config\Config.h>
#include <regex>
#include <iostream>
#include <fstream>
#include <algorithm>
using namespace std;



ostream &operator<<(ostream &os, Config& m) {
	return os << m.str;
}

bool stob(string s) {
	regex e("TRUE", std::regex_constants::icase);
	return regex_match(s, e) ? true : false;
}

double Config::GetDouble(string key, double defval = 0)   { return map[key]["DOUBLE"] == "" ? defval : stof(map[key]["DOUBLE"]); }
int    Config::GetInt(string key, int defval = 0)      { return map[key]["INT"] == "" ? defval : stoi(map[key]["INT"]); }
string Config::GetString(string key, string defval = "")  { return map[key]["STRING"] == "" ? defval : map[key]["STRING"]; }
bool   Config::GetBool(string key, bool defval = false) { return map[key]["BOOL"] == "" ? defval : stob(map[key]["BOOL"]); }

Config::Config(string path){
	this->path = path;
}

bool Config::Load(){
	ifstream t(path);

	if (!t.good()){
		return false;
	}

	string s((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
	t.close();
	//group 1,2,3,4,5 = property,float,int,string,bool
	regex expr("([\\w]+)\\s*=\\s*(?:(\\d+\\.+\\d+|\\.\\d+|\d+\\.)|(\\d+)|(\"[^\r\n:]*\")|(TRUE|FALSE))", std::regex_constants::icase);
	for (sregex_iterator it(s.begin(), s.end(), expr), itEnd; it != itEnd; it++)
	{
		string key, type, value; int i;
		if ((*it)[2].matched) { i = 2; type = "DOUBLE"; }
		else if ((*it)[3].matched) { i = 3; type = "INT"; }
		else if ((*it)[4].matched) { i = 4; type = "STRING"; }
		else                       { i = 5; type = "BOOL"; }
		key = (*it)[1].str();
		value = (*it)[i].str();
		map[key][type] = value;
		str += type + " -> " + key + " = " + value + "\n";
	}
	return true;
}


int Option::Load(std::string path){
	Config config = path;
	if (!config.Load()){
		cout << "Please Check ";
		return False;
	}

	cout << config;

	//MODULES
	this->FileOutput = config.GetBool("FileOutput");
	this->PitchDetector = config.GetBool("PitchDetector");
	this->PitchDetector = config.GetBool("PitchDetector");

	//PITCH DETECTOR
	this->AnalysisChannel = min(config.GetInt("AnalysisChannel") - 1, 0);
	this->BlockSize = config.GetInt("BlockSize", 8);
	this->Overlap = config.GetInt("Overlap", 16);
	this->NormalizeForDetection = config.GetBool("NormalizeForDetection");
	this->Pitch_Graph = config.GetInt("Pitch_Graph", 16);
	this->SineWave_Graph = config.GetBool("SineWave_Graph");
	
	//OUTPUTS
	//this->Output_PitchData = config.GetBool("Output_PitchData");

	//std::string PrefixName;
	//std::string OutputDir;
	//Store file oput
	this->PrefixName = config.GetString("OutputFile_Prefix_Name");
	this->AddPrefixName = config.GetBool("Add_Prefix_Name");
	this->OutputDir = config.GetString("OutputFile_Specific_Dir");
	this->AddAvgName = config.GetBool("Add_Avg_Pitch");
	//MovetoNewFolder;
	return 0;
}




void Option::SetOptionHelmholtz(DataChannel *opt){
	((OptionHelmholtz *)opt)->Pitch_Graph = Pitch_Graph;
	((OptionHelmholtz *)opt)->SineWave_Graph = SineWave_Graph;
	((OptionHelmholtz *)opt)->Avg_Name = AddAvgName;
}


Option::Option(){
	Pitch_Graph = 0;
	SineWave_Graph = 0;
	MovetoNewFolder = 0;
	AddPrefixName = 0;
}



DataChannel::DataChannel(){
	RawData = NULL;
	Length = 0;
	SampleRate = 0;
}
